/*
 *  Copyright (c) 2014 ZengYajian
 *
 *  Simple log module for c.
 *  by ZengYajian
 */

#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>

#include "log.h"


static struct logger _logger;

static int _write(char *buffer, int len);

int log_init(enum loglevel l, const char *name, const char *path)
{
	if (access(path, 0)) {
		if (mkdir(path, S_IREAD | S_IWRITE)<0)
			fprintf(stderr, "Create folder failed '%s'\n", path);
	}

	_logger.setting_loglevel = l;
	snprintf(_logger.location, _LOG_PATH_LEN, "%s/%s.log", path, name);

	_logger.log_file = fopen(_logger.location, "w");
	if (!_logger.log_file) {
		fprintf(stderr, "Cannot open log file '%s'\n", _logger.location);
		return -1;
	}

	/* not IO buffer */
	setvbuf(_logger.log_file, (char *)NULL, _IOLBF, 0);

	return 0;
}

const char* loglevel2str(enum loglevel l)
{
	const char *loglevel_str[] = {
		"[ERRO...]",
		"[WARNING]",
		"[NOTICE.]",
		"[TRACE..]",
		"[DEBUG..]"};

	return loglevel_str[(int)l];
}

int premakestr(char *buff, enum loglevel l)
{
	struct timeval tv;
	struct timezone tz;
	struct tm *st;

	gettimeofday(&tv, &tz);
	st = localtime(&tv.tv_sec);

	return snprintf(buff, _LOG_BUFFSIZE, "%s %02d:%02d:%02d.%06d ",
		loglevel2str(l), st->tm_hour, st->tm_min, st->tm_sec, (int)tv.tv_usec);
}

int _log(enum loglevel l, char *logformat,...)
{
	int size;
	int prestrlen = 0;
	char *p = _logger.buffer;

	prestrlen = premakestr(p, l);
	p += prestrlen;

	va_list args;
	va_start(args, logformat);
	size = vsnprintf(p, _LOG_BUFFSIZE - prestrlen, logformat, args);
	va_end(args);

	if (!_logger.log_file) {
		fprintf(stderr, "%s", _logger.buffer);
	} else {
		_write(_logger.buffer, prestrlen + size);
	}

	return 0;
}

static int _write(char *buffer, int len)
{
	int x;

	if (fwrite(buffer, len, 1, _logger.log_file)==1) {
		fflush(_logger.log_file);
		*buffer = '\0';
	} else {
		x = errno;
		fprintf(stderr, "Failed to wirte logfile, error:%s\n", strerror(x));
	}
	return 0;
}
